#include "../include/head.h"
#include "../include/thread_pool.h"
#include "../include/task_queue.h"
#include <shadow.h>
void clean_func(void* p){
    pTaskQueue_t pQue = (pTaskQueue_t)p;
    pthread_mutex_unlock(&pQue->mutex);
}
int build_filepath(Cmd_t *pcmd, char *client_path, char *out, size_t size) {
    char temp[1024] = {0};
    char final_parts[MAX_WORDNUM][MAX_WORDLEN];
    int final_count = 0;

    // 复制当前路径
    for (int i = 0; i < pcmd->c_argc; ++i) {
        strcpy(final_parts[final_count++], pcmd->_cmd[i]);
    }

    // 分割客户端输入
    char path_copy[1024];
    strncpy(path_copy, client_path, sizeof(path_copy) - 1);
    path_copy[sizeof(path_copy) - 1] = '\0';

    char *token = strtok(path_copy, "/");
    while (token) {
        if (strcmp(token, ".") == 0) {
            // 当前目录，跳过
        } else if (strcmp(token, "..") == 0) {
            // 上级目录
            if (final_count > 0) final_count--;
        } else if (strlen(token) > 0) {
            // 正常路径名
            strcpy(final_parts[final_count++], token);
        }
        token = strtok(NULL, "/");
    }

    // 生成最终路径
    snprintf(temp, sizeof(temp), "%s", HOME);
    for (int i = 0; i < final_count; ++i) {
        strncat(temp, "/", sizeof(temp) - strlen(temp) - 1);
        strncat(temp, final_parts[i], sizeof(temp) - strlen(temp) - 1);
    }

    strncpy(out, temp, size - 1);
    out[size - 1] = '\0';
    return 0;
}
void* child_handle(void* p){
    pTaskQueue_t pQue = (pTaskQueue_t)p;
    pTaskNode_t pCur = NULL;
    int fd = -1;
    int is_log = 0;
    int ret = -1;
    Truck_t train;
    Cmd_t pcmd; //只存放当前目录信息
    bzero(&pcmd,sizeof(Cmd_t));
    while(1){
        pthread_mutex_lock(&pQue->mutex);
        pthread_cleanup_push(clean_func,pQue);
        while(0==pQue->size){
            pthread_cond_wait(&pQue->cond,&pQue->mutex);
            printf("Lai huo l \n");
        }
        if(1==pQue->flag){
            printf("thread exit\n");
            fd = -1;
            pthread_exit(NULL);
        }
        get_TaskNode(pQue,&pCur);
        pthread_mutex_unlock(&pQue->mutex);
        fd = pCur->cli_fd;
        printf("client connected ...\n");
        while(1){
            bzero(&train,sizeof(Truck_t));
            ret = recv(fd,&train.truck_op,sizeof(int),0);
            if (ret == 0) {
                printf("客户端关闭连接 fd=%d\n", fd);
                close(fd);
                is_log= 0;
                fd = -1;
                break;
            }
            if(train.truck_op == OP_LOGIN){
                int ret = op_login(fd);
                if(ret == 0){
                    printf("login success\n");
                    is_log = 1;
                }
            }else if(train.truck_op == OP_CD && is_log == 1){
                recv(fd,&train.truck_len,sizeof(int),0);
                recv(fd,train.truck_data,train.truck_len,0);
                Cmd_t tmp;
                memcpy(&tmp, &pcmd, sizeof(Cmd_t));
                update_current_dir(&pcmd,train.truck_data);
                int ret = op_cd(fd,&pcmd);
                if(ret == -1){
                    pcmd = tmp;
                    for(int i = 0;i<pcmd.c_argc;++i){
                        printf("%s ",pcmd._cmd[i]);
                    }
                    printf("\n");
                }
            }else if(train.truck_op == OP_LS && is_log == 1){
                recv(fd,&train.truck_len,sizeof(int),0);

                op_ls(fd,&pcmd);    
            }else if(train.truck_op == OP_PWD && is_log == 1){
                recv(fd,&train.truck_len,sizeof(int),0);
                op_pwd(fd,&pcmd);
            }else if(train.truck_op == OP_MKDIR && is_log == 1){
                recv(fd,&train.truck_len,sizeof(int),0);

                recv(fd,train.truck_data,train.truck_len,0);
                Cmd_t tmp;
                memcpy(&tmp, &pcmd, sizeof(Cmd_t));
                update_current_dir(&tmp,train.truck_data);
                op_mkdir(fd,&tmp);
            }else if(train.truck_op == OP_RMDIR && is_log == 1){
                recv(fd,&train.truck_len,sizeof(int),0);

                recv(fd,train.truck_data,train.truck_len,0);
                Cmd_t tmp;
                memcpy(&tmp, &pcmd, sizeof(Cmd_t));
                update_current_dir(&tmp,train.truck_data);
                op_rmdir(fd,&tmp);
            }else if(train.truck_op == OP_PUTS && is_log == 1 ){
                recv(fd,&train.truck_len,sizeof(int),0);

                recv(fd,train.truck_data,train.truck_len,0);
                Cmd_t tmp;
                memcpy(&tmp,&pcmd,sizeof(Cmd_t));
                char path[1024];
                build_filepath(&tmp,train.truck_data,path,sizeof(path));
                printf("filepath=%s\n",path);
                //upload(fd,path);
                client_upload(fd,path);
            }else if(train.truck_op == OP_GETS && is_log== 1){
                recv(fd,&train.truck_len,sizeof(int),0);

                recv(fd,train.truck_data,train.truck_len,0);
                Cmd_t tmp;
                memcpy(&tmp,&pcmd,sizeof(Cmd_t));
                char path[1024];
                build_filepath(&tmp,train.truck_data,path,sizeof(path));
                printf("filepath=%s\n",path);
                download(fd,path);
            }else{
                send_truck(fd,OP_ERR,"please log in first");
            }


        }
        free(pCur);
        pCur = NULL;
        pthread_cleanup_pop(1);

    }
}


int send_truck(int fd, OP op, const char *data) {
    Truck_t msg;
    msg.truck_op = op;
    msg.truck_len = strlen(data);
    strncpy(msg.truck_data, data, BUF_SIZE - 1);
    msg.truck_data[BUF_SIZE - 1] = '\0';

    // 先发送固定头
    if (send(fd, &msg.truck_op, sizeof(msg.truck_op), 0) <= 0) return -1;
    if (send(fd, &msg.truck_len, sizeof(msg.truck_len), 0) <= 0) return -1;

    // 再发送数据
    if (send(fd, data, msg.truck_len, 0) <= 0) return -1;

    return 0;
}

int update_current_dir(Cmd_t *pcmd, char *new_path) {
    char buf[BUF_SIZE];
    strncpy(buf, new_path, sizeof(buf) - 1);
    buf[sizeof(buf) - 1] = '\0';

    // 如果是绝对路径，清空当前目录
    if (new_path[0] == '/') {
        pcmd->c_argc = 0;
    }

    char *token = strtok(buf, "/");
    while (token && pcmd->c_argc < MAX_WORDNUM) {
        if (strcmp(token, "..") == 0) {
            if (pcmd->c_argc > 0)
                pcmd->c_argc--; // 返回上一级
        } else if (strcmp(token, ".") == 0) {
            // 当前目录，跳过
        } else {
            // 新的子目录
            strncpy(pcmd->_cmd[pcmd->c_argc], token, MAX_WORDLEN - 1);
            pcmd->_cmd[pcmd->c_argc][MAX_WORDLEN - 1] = '\0';
            pcmd->c_argc++;
        }
        token = strtok(NULL, "/");
    }
    return 0;
}


// op_cd
int op_cd(int fd, Cmd_t *pcmd) {

    // 拼接服务端完整路径
    char full_path[128] = {0};
    strcpy(full_path, HOME);

    for (int i = 0; i < pcmd->c_argc; ++i) {
        if (strcmp(pcmd->_cmd[i], "") == 0) continue; 
        strcat(full_path, "/");
        strcat(full_path, pcmd->_cmd[i]);
    }

    // 尝试切换目录
    if (chdir(full_path) == -1) {
        send_truck(fd, OP_ERR, "cd failed2");
        return -1;
    }
    printf("cd fullpath = %s\n",full_path);
    // 构建发送给客户端的路径（去掉 HOME 前缀）
    char client_path[128] = {0};
    const char *p = full_path + strlen(HOME); // 从 HOME 后开始
    if (*p == '\0') strcpy(client_path, "/"); // HOME 本身目录
    else snprintf(client_path, sizeof(client_path), "%s", p);

    // 发送给客户端
    send_truck(fd, OP_SUC, client_path);

    return 0;
}

// op_ls 实现
int op_ls(int fd,Cmd_t* pcmd) {
    char full_path[256] = {0};
    strcpy(full_path, HOME);

    for (int i = 0; i < pcmd->c_argc; ++i) {
        if (strcmp(pcmd->_cmd[i], "") == 0) continue;
        strcat(full_path, "/");
        strcat(full_path, pcmd->_cmd[i]);
    }

    DIR *dir = opendir(full_path);
    if(dir == NULL){
        char err[] = "ls failed" ;
        send_truck(fd, OP_ERR, err);
        return -1;
    }
    struct dirent *entry;
    char buf[BUF_SIZE];
    int offset = 0;

    while ((entry = readdir(dir)) != NULL) {
        if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
        }

        // 计算需要写入的长度 (文件名 + '\n')
        int name_len = strlen(entry->d_name);
        int required_space = name_len + 1;

        // 检查缓冲区剩余空间是否足够
        if (offset + required_space >= BUF_SIZE) {
            // 空间不足，发送当前缓冲区内容
            send_truck(fd, OP_SUC, buf);
            offset = 0; // 重置偏移量
        }

        // 现在空间肯定足够，安全地写入
        int n = snprintf(buf + offset, sizeof(buf) - offset, "%s\n", entry->d_name);
        offset += n;
    }

    // 发送缓冲区中剩余的最后部分内容
    if (offset > 0) {
        send_truck(fd, OP_SUC, buf);
    }

    closedir(dir);
    return 0;
}
int op_pwd(int fd,Cmd_t* pcmd) {
    //    char cur[BUF_SIZE] = {0};
    //if (!getcwd(cur, sizeof(cur))) {
    //    send_truck(fd, OP_ERR, "pwd failed");
    //    return -1;
    //}

    //char result[128] = {0};
    //
    //    // 去掉 HOME 前缀
    //    if (strncmp(cur, HOME, strlen(HOME)) == 0) {
    //        const char *p = cur + strlen(HOME);
    //        if (*p == '\0') {
    //            strcpy(result, "/");  // HOME 本身
    //        } else {
    //            snprintf(result, sizeof(result), "/%s/", p);
    //        }
    //    } else {
    //        send_truck(fd, OP_ERR, "pwd failed");
    //        return -1;
    //    }
    char full_path[256] = {0};
    if(pcmd->c_argc ==0){
        send_truck(fd,OP_SUC,"/");
        return 0;
    }
    for (int i = 0; i < pcmd->c_argc; ++i) {
        if (strcmp(pcmd->_cmd[i], "") == 0) continue;
        strcat(full_path, "/");
        strcat(full_path, pcmd->_cmd[i]);
    }
    send_truck(fd, OP_SUC, full_path);
    return 0;
}
int op_mkdir(int fd, Cmd_t *pcmd) {
    // 拼接完整路径
    char full_path[256] = {0};
    strcpy(full_path, HOME);

    for (int i = 0; i < pcmd->c_argc; ++i) {
        if (strcmp(pcmd->_cmd[i], "") == 0) continue;
        strcat(full_path, "/");
        strcat(full_path, pcmd->_cmd[i]);
    }

    // 尝试创建目录
    int ret = mkdir(full_path, 0755);
    if (ret == -1) {
        send_truck(fd, OP_ERR, "mkdir failed");
        return -1;
    }

    // 构造客户端显示路径（去掉HOME前缀）
    char client_path[128] = {0};
    const char *p = full_path + strlen(HOME);
    if (*p == '\0') {
        strcpy(client_path, "/");
    }else{
        snprintf(client_path, sizeof(client_path), "/%s/", p);
    } 
    // 发送成功消息
    send_truck(fd, OP_SUC, client_path);
    return 0;
}
int op_rmdir(int fd, Cmd_t *pcmd) {
    // 拼接完整路径
    char full_path[256] = {0};
    strcpy(full_path, HOME);

    for (int i = 0; i < pcmd->c_argc;++i) {
        if (strcmp(pcmd->_cmd[i], "") == 0) continue;
        strcat(full_path, "/");
        strcat(full_path, pcmd->_cmd[i]);
    }

    // 尝试删除目录（仅能删除空目录）
    int ret = rmdir(full_path);
    if (ret == -1) {
        send_truck(fd, OP_ERR, "rmdir failed");
        return -1;
    }

    // 构造客户端显示路径（去掉HOME前缀）
    char client_path[128] = {0};
    const char *p = full_path + strlen(HOME);
    if (*p == '\0') strcpy(client_path, "/");
    else snprintf(client_path, sizeof(client_path), "/%s", p);

    // 成功反馈
    send_truck(fd, OP_SUC, client_path);
    return 0;
}
int op_login(int fd){
    Truck_t train;
    memset(&train,0,sizeof(train));
    recv(fd,&train.truck_len,sizeof(int),0);
    recv(fd,train.truck_data,train.truck_len,0);
    char username[128] = {0};
    strcpy(username,train.truck_data);
    printf("client input username = %s\n",train.truck_data);
    struct spwd *user = getspnam(train.truck_data);
    if(user == NULL){
        printf("getspam err\n");
        send_truck(fd,OP_ERR,"user is not exit!");
        return -1;
    }
    char salt[128] = {0};
    const char *pwd = user->sp_pwdp;
    int dollar_count = 0;
    int i = 0;
    for (; pwd[i] && dollar_count < 4 &&i<127; ++i) {
        salt[i] = pwd[i];
        if (pwd[i] == '$') dollar_count++;
    } 
    salt[i] = '\0';  // 确保结尾
    memset(train.truck_data,0,sizeof(train.truck_data));
    strcpy(train.truck_data,salt);
    printf("salt = %s\n",train.truck_data);
    train.truck_len = strlen(salt);
    OP op = OP_SUC;
    int ret = send(fd,&op,sizeof(int),MSG_NOSIGNAL);
    if(ret < 0){
        return -1;
    }
    ret = send(fd,&train.truck_len,sizeof(int),MSG_NOSIGNAL);
    if(ret <0){
        return -1;
    }
    ret = send(fd,train.truck_data,train.truck_len,MSG_NOSIGNAL);
    if(ret <0){
        return -1;
    }
    int rret =recv(fd,&train.truck_len,sizeof(int),0);
    if(rret == 0){
        return -1;
    }
    rret = recv(fd,train.truck_data,train.truck_len,0);
    if(rret == 0){
        return -1;
    }
    printf("crypted passwd = %s\n",train.truck_data);
    printf("mine passwd = %s\n",user->sp_pwdp);
    if(strcmp(train.truck_data,user->sp_pwdp) == 0){
        send_truck(fd,OP_SUC,"login successfully!");
        return 0;
    }else{
        send_truck(fd,OP_ERR,"login failed!");
        return -1;
    }
}
